home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / less-177.lha / less-177 / decode.c < prev    next >
C/C++ Source or Header  |  1991-03-06  |  8KB  |  369 lines

  1. /*
  2.  * Routines to decode user commands.
  3.  *
  4.  * This is all table driven.
  5.  * A command table is a sequence of command descriptors.
  6.  * Each command descriptor is a sequence of bytes with the following format:
  7.  *    <c1><c2>...<cN><0><action>
  8.  * The characters c1,c2,...,cN are the command string; that is,
  9.  * the characters which the user must type.
  10.  * It is terminated by a null <0> byte.
  11.  * The byte after the null byte is the action code associated
  12.  * with the command string.
  13.  * If an action byte is OR-ed with A_EXTRA, this indicates
  14.  * that the option byte is followed by an extra string.
  15.  *
  16.  * There may be many command tables.
  17.  * The first (default) table is built-in.
  18.  * Other tables are read in from "lesskey" files.
  19.  * All the tables are linked together and are searched in order.
  20.  */
  21.  
  22. #include "less.h"
  23. #include "cmd.h"
  24. #if __MSDOS__
  25. #include <io.h>
  26. #include <stdlib.h>
  27. #endif
  28.  
  29. /*
  30.  * Command table is ordered roughly according to expected
  31.  * frequency of use, so the common commands are near the beginning.
  32.  */
  33. static char cmdtable[] =
  34. {
  35. #if __MSDOS__
  36.     /*
  37.      * PC function keys.
  38.      * Note that '\0' is converted to '\200' on input.
  39.      */
  40.     '\200','\120',0,        A_F_LINE,        /* down arrow */
  41.     '\200','\121',0,        A_F_SCREEN,        /* page down */
  42.     '\200','\110',0,        A_B_LINE,        /* up arrow */
  43.     '\200','\111',0,        A_B_SCREEN,        /* page up */
  44.     '\200','\107',0,        A_GOLINE,        /* home */
  45.     '\200','\117',0,        A_GOEND,        /* end */
  46.     '\200','\073',0,        A_HELP,            /* F1 */
  47.     '\200','\104',0,        A_MODIFY_WINDOW,    /* F10 */
  48.     '\200','\103',0,        A_MODIFY_COLOURS,    /* F9 */
  49. #endif
  50.     '\r',0,                A_F_LINE,
  51.     '\n',0,                A_F_LINE,
  52.     'e',0,                A_F_LINE,
  53.     'j',0,                A_F_LINE,
  54.     CONTROL('E'),0,            A_F_LINE,
  55.     CONTROL('N'),0,            A_F_LINE,
  56.     'k',0,                A_B_LINE,
  57.     'y',0,                A_B_LINE,
  58.     CONTROL('Y'),0,            A_B_LINE,
  59.     CONTROL('K'),0,            A_B_LINE,
  60.     CONTROL('P'),0,            A_B_LINE,
  61.     'J',0,                A_FF_LINE,
  62.     'K',0,                A_BF_LINE,
  63.     'Y',0,                A_BF_LINE,
  64.     'd',0,                A_F_SCROLL,
  65.     CONTROL('D'),0,            A_F_SCROLL,
  66.     'u',0,                A_B_SCROLL,
  67.     CONTROL('U'),0,            A_B_SCROLL,
  68.     ' ',0,                A_F_SCREEN,
  69.     'f',0,                A_F_SCREEN,
  70.     CONTROL('F'),0,            A_F_SCREEN,
  71.     CONTROL('V'),0,            A_F_SCREEN,
  72.     'b',0,                A_B_SCREEN,
  73.     CONTROL('B'),0,            A_B_SCREEN,
  74.     ESC,'v',0,            A_B_SCREEN,
  75.     'z',0,                A_F_WINDOW,
  76.     'w',0,                A_B_WINDOW,
  77.     'F',0,                A_F_FOREVER,
  78.     'R',0,                A_FREPAINT,
  79.     'r',0,                A_REPAINT,
  80.     CONTROL('R'),0,            A_REPAINT,
  81.     CONTROL('L'),0,            A_REPAINT,
  82.     'g',0,                A_GOLINE,
  83.     '<',0,                A_GOLINE,
  84.     ESC,'<',0,            A_GOLINE,
  85.     'p',0,                A_PERCENT,
  86.     '%',0,                A_PERCENT,
  87.     '{',0,                A_F_BRACKET|A_EXTRA,    '{','}',0,
  88.     '}',0,                A_B_BRACKET|A_EXTRA,    '{','}',0,
  89.     '(',0,                A_F_BRACKET|A_EXTRA,    '(',')',0,
  90.     ')',0,                A_B_BRACKET|A_EXTRA,    '(',')',0,
  91.     '[',0,                A_F_BRACKET|A_EXTRA,    '[',']',0,
  92.     ']',0,                A_B_BRACKET|A_EXTRA,    '[',']',0,
  93.     ESC,CONTROL('F'),0,        A_F_BRACKET,
  94.     ESC,CONTROL('B'),0,        A_B_BRACKET,
  95.     'G',0,                A_GOEND,
  96.     ESC,'>',0,            A_GOEND,
  97.     '>',0,                A_GOEND,
  98.     'P',0,                A_GOPOS,
  99.  
  100.     '0',0,                A_DIGIT,
  101.     '1',0,                A_DIGIT,
  102.     '2',0,                A_DIGIT,
  103.     '3',0,                A_DIGIT,
  104.     '4',0,                A_DIGIT,
  105.     '5',0,                A_DIGIT,
  106.     '6',0,                A_DIGIT,
  107.     '7',0,                A_DIGIT,
  108.     '8',0,                A_DIGIT,
  109.     '9',0,                A_DIGIT,
  110.  
  111.     '=',0,                A_STAT,
  112.     CONTROL('G'),0,            A_STAT,
  113.     ':','f',0,            A_STAT,
  114.     '/',0,                A_F_SEARCH,
  115.     '?',0,                A_B_SEARCH,
  116.     ESC,'/',0,            A_F_SEARCH|A_EXTRA,    '*',0,
  117.     ESC,'?',0,            A_B_SEARCH|A_EXTRA,    '*',0,
  118.     'n',0,                A_AGAIN_SEARCH,
  119.     ESC,'n',0,            A_T_AGAIN_SEARCH,
  120.     'N',0,                A_REVERSE_SEARCH,
  121.     ESC,'N',0,            A_T_REVERSE_SEARCH,
  122.     'm',0,                A_SETMARK,
  123.     '\'',0,                A_GOMARK,
  124.     CONTROL('X'),CONTROL('X'),0,    A_GOMARK,
  125.     'E',0,                A_EXAMINE,
  126.     ':','e',0,            A_EXAMINE,
  127.     CONTROL('X'),CONTROL('V'),0,    A_EXAMINE,
  128.     ':','n',0,            A_NEXT_FILE,
  129.     ':','p',0,            A_PREV_FILE,
  130.     ':','x',0,            A_INDEX_FILE,
  131.     '-',0,                A_OPT_TOGGLE,
  132.     ':','t',0,            A_OPT_TOGGLE|A_EXTRA,    't',0,
  133.     's',0,                A_OPT_TOGGLE|A_EXTRA,    'o',0,
  134.     '_',0,                A_DISP_OPTION,
  135.     '|',0,                A_PIPE,
  136.     'v',0,                A_VISUAL,
  137.     '!',0,                A_SHELL,
  138.     '+',0,                A_FIRSTCMD,
  139.  
  140.     'H',0,                A_HELP,
  141.     'h',0,                A_HELP,
  142.     'V',0,                A_VERSION,
  143.     'q',0,                A_QUIT,
  144.     ':','q',0,            A_QUIT,
  145.     ':','Q',0,            A_QUIT,
  146.     'Z','Z',0,            A_QUIT,
  147.     ESC,ESC,0,            A_QUIT,
  148. };
  149.  
  150. /*
  151.  * Structure to support a list of command tables.
  152.  */
  153. struct tablelist
  154. {
  155.     struct tablelist *t_next;
  156.     char *t_start;
  157.     char *t_end;
  158. };
  159.  
  160. /*
  161.  * Structure for the default command table.
  162.  */
  163. static struct tablelist deftable = 
  164.     { NULL, cmdtable, cmdtable+sizeof(cmdtable) };
  165.  
  166. /*
  167.  * List of tables; initially contains only the default table.
  168.  */
  169. static struct tablelist *tables = &deftable;
  170.  
  171. static int cmd_search();
  172.  
  173. extern int erase_char, kill_char;
  174.  
  175. /*
  176.  * Decode a command character and return the associated action.
  177.  * The "extra" string, if any, is returned in sp.
  178.  */
  179.     public int
  180. cmd_decode(cmd, sp)
  181.     char *cmd;
  182.     char **sp;
  183. {
  184.     register struct tablelist *t;
  185.     register int action;
  186.  
  187.     /*
  188.      * Search thru all the command tables.
  189.      * Stop when we find an action which is not A_INVALID.
  190.      */
  191.     for (t = tables;  t != NULL;  t = t->t_next)
  192.     {
  193.         action = cmd_search(cmd, t->t_start, t->t_end, sp);
  194.         if (action != A_INVALID)
  195.             break;
  196.     }
  197.     return (action);
  198. }
  199.  
  200. /*
  201.  * Search a command table for the current command string (in cmd).
  202.  */
  203.     static int
  204. cmd_search(cmd, table, endtable, sp)
  205.     char *cmd;
  206.     char *table;
  207.     char *endtable;
  208.     char **sp;
  209. {
  210.     register char *p;
  211.     register char *q;
  212.     register int a;
  213.  
  214.     for (p = table, q = cmd;  p < endtable;  p++, q++)
  215.     {
  216.         if (*p == *q)
  217.         {
  218.             /*
  219.              * Current characters match.
  220.              * If we're at the end of the string, we've found it.
  221.              * Return the action code, which is the character
  222.              * after the null at the end of the string
  223.              * in the command table.
  224.              */
  225.             if (*p == '\0')
  226.             {
  227.                 a = *++p & 0377;
  228.                 /*
  229.                  * Check for an "extra" string.
  230.                  */
  231.                 if (a & A_EXTRA)
  232.                 {
  233.                     *sp = ++p;
  234.                     a &= ~A_EXTRA;
  235.                 } else
  236.                     *sp = NULL;
  237.                 return (a);
  238.             }
  239.         } else if (*q == '\0')
  240.         {
  241.             /*
  242.              * Hit the end of the user's command,
  243.              * but not the end of the string in the command table.
  244.              * The user's command is incomplete.
  245.              */
  246.             return (A_PREFIX);
  247.         } else
  248.         {
  249.             /*
  250.              * Not a match.
  251.              * Skip ahead to the next command in the
  252.              * command table, and reset the pointer
  253.              * to the beginning of the user's command.
  254.              */
  255.             while (*p++ != '\0') ;
  256.             if (*p & A_EXTRA)
  257.                 while (*++p != '\0') ;
  258.             q = cmd-1;
  259.         }
  260.     }
  261.     /*
  262.      * No match found in the entire command table.
  263.      */
  264.     return (A_INVALID);
  265. }
  266.  
  267. #if USERFILE
  268. /*
  269.  * Set up a user command table, based on a "lesskey" file.
  270.  */
  271.     public int
  272. add_cmdtable(filename)
  273.     char *filename;
  274. {
  275.     register struct tablelist *t;
  276.     register POSITION len;
  277.     register long n;
  278.     register int f;
  279.  
  280.     /*
  281.      * Try to open the lesskey file.
  282.      * If we can't, return an error.
  283.      */
  284.     f = open(filename, 0);
  285.     if (f < 0)
  286.         return (-1);
  287.  
  288.     /*
  289.      * Read the file into the user table.
  290.      * We first figure out the size of the file and allocate space for it.
  291.      * {{ Minimal error checking is done here.
  292.      *    A garbage .less file will produce strange results.
  293.      *    To avoid a large amount of error checking code here, we
  294.      *    rely on the lesskey program to generate a good .less file. }}
  295.      */
  296.     len = filesize(f);
  297.     if (len == NULL_POSITION || len < 3)
  298.     {
  299.         /*
  300.          * Bad file (valid file must have at least 3 chars).
  301.          */
  302.         close(f);
  303.         return (-1);
  304.     }
  305.     if ((t = (struct tablelist *) 
  306.             calloc(1, sizeof(struct tablelist))) == NULL)
  307.     {
  308.         close(f);
  309.         return (-1);
  310.     }
  311.     if ((t->t_start = (char *) calloc(len, sizeof(char))) == NULL)
  312.     {
  313.         free((char *)t);
  314.         close(f);
  315.         return (-1);
  316.     }
  317.     if (lseek(f, (offset_t)0, 0) == BAD_LSEEK)
  318.     {
  319.         free(t->t_start);
  320.         free((char *)t);
  321.         close(f);
  322.         return (-1);
  323.     }
  324.     n = read(f, t->t_start, (unsigned int) len);
  325.     close(f);
  326.  
  327.     /*
  328.      * In a valid lesskey file, the last byte or 
  329.      * the second to the last byte must be zero.
  330.      */
  331.     if (n != len || (t->t_start[n-1] != '\0' && t->t_start[n-2] != '\0'))
  332.     {
  333.         free(t->t_start);
  334.         free((char *)t);
  335.         return (-1);
  336.     }
  337.     t->t_end = t->t_start + n;
  338.  
  339.     /*
  340.      * Link it into the list of tables.
  341.      */
  342.     t->t_next = tables;
  343.     tables = t;
  344.     return (0);
  345. }
  346.  
  347. /*
  348.  * Try to add the lesskey file "$HOME/.less"
  349.  */
  350.     public void
  351. add_hometable()
  352. {
  353.     char *filename;
  354.  
  355. #if __MSDOS__
  356.     filename = homefile("_less");
  357. #else
  358.     filename = homefile(".less");
  359. #endif
  360.     if (filename == NULL)
  361.         return;
  362.     /*
  363.      * Ignore errors.
  364.      */
  365.     (void) add_cmdtable(filename);
  366.     free(filename);
  367. }
  368. #endif
  369.